/*
 * Copyright 2010 Christoph Widulle (christoph.widulle@googlemail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */


package com.android1.amarena2d.nodes;

import com.android1.amarena2d.commons.Offset;
import com.android1.amarena2d.commons.Size;
import com.android1.amarena2d.nodes.behavior.*;
import com.android1.amarena2d.nodes.behavior.delegates.*;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;

public abstract class BaseActionEntity extends BaseLifecycleObject implements Entity, ActionTarget, Transformable, Syncable, HasBounds, HasVolumne, Tagged {

    protected final Vector2 position = new Vector2();
    protected Offset offset;
    protected final Size size = new Size();
    protected final Color color = new Color(Color.WHITE);

    protected TouchDelegate touchDelegate;
    protected TransformDelegate transformDelegate;
    protected ActionDelegate actionDelegate;
    protected DynamicsDelegate dynamics;
    protected SyncDelegate syncDelegate;
    protected BoundsDelegate boundsDelegate;
    protected VolumneDelegate volumneDelegate;

    protected boolean disableCulling;


    @Override
    public TransformDelegate transform() {
        if (transformDelegate == null)
            transformDelegate = new DefaultTransformDelegate(this);
        return transformDelegate;
    }

    public ActionDelegate action() {
        if (actionDelegate == null)
            actionDelegate = new ActionDelegate(this);
        return actionDelegate;
    }

    public DynamicsDelegate move() {
        if (dynamics == null)
            dynamics = new DynamicsDelegateImpl(this);
        return dynamics;
    }

    @Override
    public SyncDelegate sync() {
        if (syncDelegate == null)
            syncDelegate = new SyncDelegateImpl(this);
        return syncDelegate;
    }

    @Override
    public BoundsDelegate bounds() {
        if (boundsDelegate == null)
            boundsDelegate = new BoundsDelegateImpl();
        return boundsDelegate;
    }

    @Override
    public VolumneDelegate volumne() {
        if (volumneDelegate == null)
            volumneDelegate = new VolumneDelegate();
        return volumneDelegate;
    }

    @Override
    public boolean hasVolumne() {
        return volumneDelegate != null;
    }

    public void resumeAllActions() {
        if (actionDelegate != null)
            actionDelegate.resumeAll();
        else if (engine.getActionManager().hasTargetActionsStore(this))
            engine.getActionManager().resumeAllActions(this);

    }

    public void pauseAllActions() {
        if (actionDelegate != null)
            actionDelegate.pauseAll();
        else if (engine.getActionManager().hasTargetActionsStore(this))
            engine.getActionManager().pauseAllActions(this);
    }


    @Override
    public void dispose() {
        if (touchDelegate != null) {
            touchDelegate.revokeTouchable();
            touchDelegate = null;
        }
        super.dispose();
    }

    @Override
    public void exit() {
        pauseAllActions();
        if (touchDelegate != null)
            touchDelegate.pause();
        super.exit();
    }

    @Override
    public void enter() {
        resumeAllActions();
        if (touchDelegate != null)
            touchDelegate.resume();
        super.enter();
    }

    public void setDisableCulling(boolean disableCulling) {
        this.disableCulling = disableCulling;
    }

    public boolean isDisableCulling() {
        return disableCulling;
    }

    public boolean isVisibleOnScreen() {
        //todo calc rotation
        return Scene.CAM.isVisible(getAbsoluteMinX(), getAbsoluteMaxY(), getAbsoluteMaxX(), getAbsoluteMinY());
    }

    @Override
    public float getAbsoluteMaxX() {
        return getAbsoluteX() + getWidth();
    }

    @Override
    public float getAbsoluteMinX() {
        return getAbsoluteX();
    }

    @Override
    public float getAbsoluteMinY() {
        return getAbsoluteY();
    }


    @Override
    public float getAbsoluteMaxY() {
        return getAbsoluteY() + getHeight();
    }


    public float getBaseX() {
        return position.x;
    }


    public float getBaseY() {
        return position.y;
    }

    @Override
    public float getX() {
        if (offset != null)
            return position.x + offset.getX();
        else
            return position.x;
    }

    @Override
    public float getY() {
        if (offset != null)
            return position.y + offset.getY();
        else
            return position.y;
    }

    public Offset getOffset() {
        return offset;
    }

    public void setOffset(Vector2 offset) {
        if (this.offset == null)
            this.offset = new Offset();
        this.offset.set(offset);
    }

    public void setOffset(Vector2 offset, float scale) {
        if (this.offset == null)
            this.offset = new Offset();
        this.offset.set(offset);
        this.offset.setScale(scale);
    }

    public Vector2 getXY() {
        return position;
    }

    @Override
    public float getAbsoluteX() {
        return getX();
    }

    @Override
    public float getAbsoluteY() {
        return getY();
    }

    public float getBaseWidth() {
        return size.width;
    }

    public float getBaseHeight() {
        return size.height;
    }

    @Override
    public float getWidth() {
        if (transformDelegate != null && transformDelegate.isScaled())
            return size.width * transformDelegate.getScaleX();
        return size.width;
    }

    @Override
    public float getHeight() {
        if (transformDelegate != null && transformDelegate.isScaled())
            return size.height * transformDelegate.getScaleY();
        return size.height;
    }

    public void setAbsoluteX(final float x) {
        setXY(x, position.y);
    }

    public void setAbsoluteY(final float y) {
        setXY(position.x, y);
    }

    public void setXY(float x, float y) {

        if (boundsDelegate != null) {
            x = boundsDelegate.getSaveX(x, getWidth());
            y = boundsDelegate.getSaveY(y, getHeight());
        }
        position.x = x;
        position.y = y;
        if (syncDelegate != null && syncDelegate.internal().hasSyncPositionListener()) {
            syncDelegate.internal().firePosUpdate(x, y);
        }
    }

    public BaseActionEntity xy(float x, float y) {
        setXY(x, y);
        return this;
    }

    public void setX(final float x) {
        setXY(x, position.y);
    }

    public void setY(final float y) {
        setXY(position.x, y);
    }

    @Override
    public void addX(float x) {
        setX(getX() + x);
    }

    @Override
    public void addY(float y) {
        setY(getY() + y);
    }

    @Override
    public void addXY(float x, float y) {
        setXY(getX() + x, getY() + y);
    }

    @Override
    public float getOrigionX() {
        return getX() + getWidth() / 2;
    }

    @Override
    public float getOrigionY() {
        return getY() + getHeight() / 2;
    }

    @Override
    public void setOrigionXY(float x, float y) {
        setXY(x - getWidth() / 2, y - getHeight() / 2);
    }

    @Override
    public void setSize(final float width, final float height) {
        size.width = width;
        size.height = height;
        if (syncDelegate != null && syncDelegate.internal().hasSyncPositionListener()) {
            syncDelegate.internal().fireSizeUpdate(width, height);
        }
    }

    @Override
    public void setWidth(float width) {
        setSize(width, size.height);
    }

    @Override
    public void setHeight(float height) {
        setSize(size.width, height);
    }

    public Color getColor() {
        return color;
    }

    public void setColor(final float r, final float g, final float b) {
        color.r = r;
        color.g = g;
        color.b = b;
    }

    public void setColor(final Color color) {
        this.color.r = color.r;
        this.color.g = color.g;
        this.color.b = color.b;
    }

    public float getAlpha() {
        return color.a;
    }

    public void setAlpha(float a) {
        color.a = a;
    }


    public void setActive(boolean active) {
        this.active = active;
    }

    @Override
    public float getScaleX() {
        if (transformDelegate != null)
            return transform().getScaleX();
        else
            return 1F;
    }

    @Override
    public float getScaleY() {
        if (transformDelegate != null)
            return transform().getScaleY();
        else
            return 1F;
    }

    @Override
    public void setScaleX(float x) {
        transform().setScaleX(x);
    }

    @Override
    public void setScaleY(float y) {
        transform().setScaleY(y);
    }

    @Override
    public void setScaleXY(float scale) {
        transform().setScale(scale);
    }


    @Override
    public void rotateBy(float rotation) {
        transform().rotate(rotation);
    }

    @Override
    public void setRotation(float rotation) {
        transform().setRotation(rotation);
    }

    @Override
    public float getRotation() {
        if (transformDelegate == null)
            return 0;
        else
            return transform().getRotation();
    }

    @Override
    public void translateToLocalCoords(Vector2 out) {
        if (transformDelegate == null || !transformDelegate.isTransform()) {
            out.x = out.x - getX();
            out.y = out.y - getY();
        } else {
            transformDelegate.transformCoords(out);
        }
    }

    @Override
    public boolean isTransformed() {
        return transformDelegate != null && transformDelegate.isTransform();
    }

    @Override
    public void setTag(String tag) {
        super.setTag(tag);
    }

    public boolean isTouchable() {
        return touchDelegate != null && touchDelegate.isActive();
    }

    public boolean onTouchDown(float x, float y, int pointer, boolean isHit) {
        return false;
    }

    public boolean onTouchUp(float x, float y, int pointer, boolean isHit) {
        return false;
    }

    public boolean onTouchDragged(float x, float y, int pointer, boolean isHit) {
        return false;
    }
}